#include "public_method.h"
#include "utils.h"

#define QUEUE 20

const char *log_path = "./log/log.txt";

void error_die(const char* str) {
	perror(str);
	exit(1);
}

// 服务器不支持请求类型
void unimplement(int client) {
	// 向指定套接字，发送一个提示-还没有实现的错误页面
	char buff[1024] = { 0 };

	strcpy(buff, "HTTP/1.1 502 Bad Gateway\r\n");
	send(client, buff, strlen(buff), 0);

	strcpy(buff, "Server: TestHttp/1.0\r\n");
	send(client, buff, strlen(buff), 0);

	strcpy(buff, "Content-Type: text/html; charset=utf-8\r\n");
	send(client, buff, strlen(buff), 0);

	strcpy(buff, "\r\n");
	send(client, buff, strlen(buff), 0);

	// 找到502页面
	FILE* resource = fopen("htdocs/502.html", "rb");

	while (true)
	{
		int ret = fread(buff, sizeof(char), sizeof(buff), resource);
		// 没有读取到
		if (ret <= 0) {
			break;
		}
		send(client, buff, ret, 0);
	}
}


/******************************
 *实现网络初始化，返回服务器端套接字
 *参数：*port端口值，为0则自动分配一个可用端口
 *****************************/
int startup(unsigned short* port){

    bool flog = log_open(log_path);
    if(!flog){
        perror("日志文件打开失败\n");
        return -1;
    }

    int listen_sock = socket(PF_INET,SOCK_STREAM,0);
    if(listen_sock == -1){
        perror("创建监听socket失败\n");
        return -1;
    }
    int opt = 1,ret = 0;
    //设置端口复用
    ret = setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,(const char *)&opt,sizeof(opt));
    if(ret == -1){
        perror("socket设置失败\n");
        return -1;
    }

    struct sockaddr_in server_sockaddr;
    bzero(&server_sockaddr,sizeof(server_sockaddr));
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(*port);
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if(bind(listen_sock,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1){
        perror("端口绑定失败\n");
        return -1;
    }

    socklen_t nameLen = sizeof(server_sockaddr);
    if(*port==0){
        if(getsockname(listen_sock,(struct sockaddr *)&server_sockaddr,&nameLen)<0){
            perror("分配端口失败\n");
            return -1;
        }
        *port = server_sockaddr.sin_port;//获取真正的端口
    }

    if(listen(listen_sock,QUEUE)==-1){
        perror("设置监听失败\n");
        return -1;
    }

    return listen_sock;
}

/*
* 处理用户请求的线程
*/
unsigned int accept_request(void* arg) {

	Http* app = getHttp();

	socket client = (int)arg; // 客户端套接字

	// 请求
	Request request(client);
	// 响应
	Response response(request, app->getStatic());
	//cout << "methods:" << request.getMethods() << "  " << "path:" << request.path << endl;


	// 判断是否是 GET 或者 POST 请求
	if (request.getMethods() != "GET" && request.getMethods() != "POST") {
		// 向浏览器返回一个错误页面
		unimplement(client);
		closesocket(client);
		return 0;
	}

	HandleFUNC allFunc = app->all("*");
	if (allFunc) {
		allFunc(request, response);
	}
	allFunc = app->all(request.path);
	if (allFunc) {
		allFunc(request, response);
	}

	if (request.getMethods() == "GET") {
		allFunc = app->get(request.path);
		if (allFunc) {
			allFunc(request, response);
		}
		else {
			// 静态资源
			response.send();
		}

	} else if (request.getMethods() == "POST") {
		allFunc = app->post(request.path);
		if (allFunc) {
			allFunc(request, response);
		}
	}

	PRINTF(request.getUrl().c_str());

	//关闭客户端socket
	close(client);
	return 0;
}

/**
* 监听套接字
*/
void listenSocket(unsigned short port) {
	/*初始化socket*/
	int serverfd = startup(&port);

	printf(u8"http服务器初始化，正在监听%d端口... \n", port);

	struct sockaddr_in client_addr; // 客户端信息
	socklen_t client_addr_len = sizeof(client_addr);
    pthread_t pid;
	// 循环等待套接字
	while (true)
	{
		// 阻塞式等待用户通过浏览器发送请求
		int connectfd = accept(serverfd, (struct sockaddr*)&client_addr, &client_addr_len);
		if (connectfd == -1) {
			error_die("accept");
		}
		// 创建一个新进程处理客户端请求
        if(pthread_create(&pid,NULL,accept_request,(void *)&connectfd) != 0){
            close(connectfd);
            error_die("thread create");
        }
	}

	// 退出服务端套接字
    //log_close();
	close(serverfd);
}

